/**
 *
 * @author Patricia Blanco created 2013 copyright 2013
 */
package dieci.database.sales;

import dieci.database.PersistentObject;
import dieci.database.SessionFactoryUtil;
import dieci.hibernate.HibSaleDetails;
import dieci.hibernate.HibSale;
import dieci.managers.clientmanager.ClientManager;
import dieci.managers.stockmanager.ProductManager;
import dieci.system.Client;
import dieci.system.Product;
import dieci.system.Sale;
import dieci.system.SaleDetails;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.hibernate.Session;
import java.util.logging.Logger;
import org.hibernate.criterion.Restrictions;

public class SaleHibernateDAO implements SaleDAO
{

    private static Logger logger = Logger.getLogger("SaleDAO.log");
    private ProductManager productManager = new ProductManager();
    private ClientManager clientManager = new ClientManager();
    
    @Override
    public List<Sale> list()
    {
        List<Sale> sales = new ArrayList<>();

        Session session = SessionFactoryUtil.getInstance().getCurrentSession();
        try {
            session.beginTransaction();

            List<HibSale> hibSales = session.createCriteria(HibSale.class).list();
            for (HibSale dbSale : hibSales) {
                Set<SaleDetails> details = new HashSet<>();
                for (HibSaleDetails hibSaleDetails : dbSale.getDetails()) {
                    Product product = findProductById(hibSaleDetails.getId().getProductId());
                    details.add(new SaleDetails(product, hibSaleDetails.getAmount(), hibSaleDetails.getPrice()));
                }
                Client client = clientManager.findById(dbSale.getClientId());
                Sale sale = new Sale(client, dbSale.getSaleDate(), 
                        details, dbSale.getDiscount(), dbSale.getDiscountType(), dbSale.getTotalSaleAmount(), 
                        dbSale.isCharged(), dbSale.isDelivered());
                sale.setSaleId(dbSale.getSaleId());
                sales.add(sale);
            }

            return sales;
        }
        catch (Exception e) {

            logger.log(Level.INFO, "Error listando", e.getMessage());

            throw new IllegalStateException("Error al listar",e);
        }
        finally {
            if (session!=null && session.isOpen()) {

                session.close();
            }
        }
    }
   

    @Override
    public Sale findBySaleId(long id)
    {
        Sale result = null;
        Session session = SessionFactoryUtil.getInstance().getCurrentSession();
        try {
            session.beginTransaction();

            HibSale hibSale = (HibSale) session.createCriteria(HibSale.class).add(Restrictions.eq("saleId", id)).uniqueResult();
            if (hibSale != null) {
                Set<SaleDetails> details = new HashSet<>();
                for (HibSaleDetails detail : hibSale.getDetails()) {
                    Product product = findProductById(detail.getId().getProductId());
                    SaleDetails p = new SaleDetails(detail.getId().getSaleId(), product, 
                            detail.getAmount(), detail.getPrice());
                    details.add(p);
                }
                Client client = clientManager.findById(hibSale.getClientId());
                result = new Sale(client, hibSale.getSaleDate(), details, 
                        hibSale.getDiscount(), hibSale.getDiscountType(), hibSale.getTotalSaleAmount(), 
                        hibSale.isCharged(),hibSale.isDelivered());
                result.setSaleId(hibSale.getSaleId());
            }

        }
        catch (Exception e) {
            throw new IllegalStateException("Error al buscar por id",e);
        }
        finally {
            if (session!=null && session.isOpen()) {

                session.close();
            }
        }

        return result;
    }


    @Override
    public void delete(PersistentObject object)
    {
        Session session = null;

        Sale sale = (Sale) object;
        Sale found = findBySaleId(sale.getSaleId());
        try {
            session = SessionFactoryUtil.getInstance().getCurrentSession();
            
            session.beginTransaction();

            if (found != null) 
            {
                //DELETE
                sale.setSaleId(found.getSaleId());

                Set<HibSaleDetails> hibSaleDetailss = new HashSet<>();
                for (SaleDetails detail : sale.getDetails()) {
                    HibSaleDetails p = new HibSaleDetails(detail, sale.getSaleId());
                    hibSaleDetailss.add(p);
                }
                HibSale hibSale = new HibSale(sale.getSaleId(), (Sale) sale);
                hibSale.setDetails(hibSaleDetailss);
                session.delete(hibSale);

            }
            
            session.getTransaction().commit();

        }
        catch (Exception e) {
            if(session!=null){
                session.getTransaction().rollback();
            }            
            throw new IllegalStateException("Error al eliminar",e);
        }
        finally {
            if (session!=null && session.isOpen()) {

                session.close();
            }
        }
    }

    @Override
    public void saveOrUpdate(PersistentObject object)
    {
        Session session = null;

        Sale sale = (Sale) object;
        Sale found = null;
        
        if(sale.getSaleId() > 0)
        {
            found = findBySaleId(sale.getSaleId());
        }
        
        try {
            session = SessionFactoryUtil.getInstance().getCurrentSession();
            
            session.beginTransaction();

            if (found != null) 
            {
                //UPDATE
                sale.setSaleId(found.getSaleId());

                Set<HibSaleDetails> hibSaleDetailss = new HashSet<>();
                for (SaleDetails detail : sale.getDetails()) {
                    HibSaleDetails d = new HibSaleDetails(detail, sale.getSaleId());
                    hibSaleDetailss.add(d);
                }
                HibSale hibSale = new HibSale(sale.getSaleId(), (Sale) sale);
                hibSale.setDetails(hibSaleDetailss);
                session.saveOrUpdate(hibSale);

            }
            else 
            {
                //NEW
                HibSale hibSale = new HibSale(sale);

                // generate new id for the saleuct
                session.save(hibSale);
                // add the details
                for (SaleDetails detail : sale.getDetails()) {
                    hibSale.getDetails().add(
                            new HibSaleDetails(detail, hibSale.getSaleId()));
                }

                // If the enty already exist update it.
                session.saveOrUpdate(hibSale);
            }

            session.getTransaction().commit();

        }
        catch (Exception e) {
            if(session!=null){
                session.getTransaction().rollback();
            }            
            throw new IllegalStateException("Error al guardar o actualizar",e);
        }
        finally {
            if (session!=null && session.isOpen()) {

                session.close();
            }
        }
    }

    @Override
    public List<Sale> findBySaleDateRange(Date start, Date end)
    {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
    

    @Override
    public List<Sale> findByClient(Client client)
    {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
    
    
    private Product findProductById(long id)
    {
        return productManager.findById(id);
    }

}
